Contents

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import warnings

# Unterdrücke Warnungen zu Teilung durch Null
warnings.filterwarnings('ignore')

def f(x, y):
    """
    Die unstetige Funktion f(x,y) = xy/(x^2 + y^2) für (x,y) ≠ (0,0) und f(0,0) = 0
    """
    # Erstelle eine Kopie des Ergebnisses, um die ursprünglichen Arrays nicht zu verändern
    result = np.zeros_like(x, dtype=float)
    
    # Berechne die Funktion für alle Punkte außer (0,0)
    # Verwende eine Maske, um Punkte zu identifizieren, die nicht (0,0) sind
    mask = (x != 0) | (y != 0)
    result[mask] = (x[mask] * y[mask]) / (x[mask]**2 + y[mask]**2)
    
    # Der Wert an (0,0) ist definiert als 0
    # Da result bereits mit Nullen initialisiert wurde, müssen wir nichts mehr tun
    
    return result

# Gitterparameter
n = 100  # Anzahl der Punkte in jeder Dimension
x_min, x_max = -1.0, 1.0
y_min, y_max = -1.0, 1.0

# Erstelle das Gitter
x = np.linspace(x_min, x_max, n)
y = np.linspace(y_min, y_max, n)
X, Y = np.meshgrid(x, y)

# Berechne die Funktionswerte
Z = f(X, Y)

# Begrenze die Werte für eine bessere Visualisierung
# Die Funktion kann extreme Werte nahe der Singularität annehmen
Z = np.clip(Z, -1, 1)

# Erstelle die Plots
plt.figure(figsize=(15, 10))

# 1. 3D-Oberflächenplot
ax1 = plt.subplot(221, projection='3d')
surf = ax1.plot_surface(X, Y, Z, cmap=cm.viridis, edgecolor='none', alpha=0.8)
ax1.set_xlabel('x-Achse')
ax1.set_ylabel('y-Achse')
ax1.set_zlabel('f(x,y)')
ax1.set_title('3D-Darstellung: f(x,y) = xy/(x² + y²)')
ax1.set_zlim(-1, 1)
plt.colorbar(surf, ax=ax1, shrink=0.5, aspect=5)

# 2. Höhenliniendiagramm (Contour-Plot)
ax2 = plt.subplot(222)
contour = ax2.contourf(X, Y, Z, 20, cmap=cm.viridis)
ax2.set_xlabel('x-Achse')
ax2.set_ylabel('y-Achse')
ax2.set_title('Höhenlinien: f(x,y) = xy/(x² + y²)')
plt.colorbar(contour, ax=ax2)
ax2.grid(True)
ax2.set_aspect('equal')

# 3. Grenzwertuntersuchung entlang verschiedener Pfade
plt.subplot(223)

# Pfad entlang der x-Achse (y=0)
t = np.linspace(0.001, 1, 100)  # Kleine Werte nahe Null, aber nicht Null selbst
x_path = t
y_path = np.zeros_like(t)
z_path = f(x_path, y_path)
plt.plot(t, z_path, 'r-', label='Entlang x-Achse (y=0)')

# Pfad entlang der y-Achse (x=0)
x_path = np.zeros_like(t)
y_path = t
z_path = f(x_path, y_path)
plt.plot(t, z_path, 'g-', label='Entlang y-Achse (x=0)')

# Pfad entlang der Diagonalen y=x
x_path = t
y_path = t
z_path = f(x_path, y_path)
plt.plot(t, z_path, 'b-', label='Entlang y=x')

# Pfad entlang y=2x
x_path = t
y_path = 2*t
z_path = f(x_path, y_path)
plt.plot(t, z_path, 'm-', label='Entlang y=2x')

plt.title('Grenzwerte entlang verschiedener Pfade')
plt.xlabel('Abstand vom Ursprung')
plt.ylabel('Funktionswert f(x,y)')
plt.grid(True)
plt.legend()
plt.axhline(y=0, color='k', linestyle='--', alpha=0.3)

# 4. Zoom auf den Bereich um (0,0)
ax4 = plt.subplot(224)
x_zoom = np.linspace(-0.2, 0.2, n)
y_zoom = np.linspace(-0.2, 0.2, n)
X_zoom, Y_zoom = np.meshgrid(x_zoom, y_zoom)
Z_zoom = f(X_zoom, Y_zoom)
Z_zoom = np.clip(Z_zoom, -1, 1)

contour_zoom = ax4.contourf(X_zoom, Y_zoom, Z_zoom, 20, cmap=cm.viridis)
ax4.set_xlabel('x-Achse')
ax4.set_ylabel('y-Achse')
ax4.set_title('Zoom auf den Bereich um (0,0)')
plt.colorbar(contour_zoom, ax=ax4)
ax4.grid(True)
ax4.set_aspect('equal')

plt.tight_layout()
plt.savefig('unstetige_funktion.png', dpi=300, bbox_inches='tight')
plt.show()
../_images/19ad08365323b2f671ca79ad73e32bccafb75e81033f69c1efbc00d4586178cc.png
import numpy as np
import plotly.graph_objects as go

def f(x, y):
    """
    Die unstetige Funktion f(x,y) = xy/(x^2 + y^2) für (x,y) ≠ (0,0) und f(0,0) = 0
    """
    # Erstelle eine Kopie des Ergebnisses, um die ursprünglichen Arrays nicht zu verändern
    result = np.zeros_like(x, dtype=float)
    
    # Berechne die Funktion für alle Punkte außer (0,0)
    # Verwende eine Maske, um Punkte zu identifizieren, die nicht (0,0) sind
    mask = (x != 0) | (y != 0)
    result[mask] = (x[mask] * y[mask]) / (x[mask]**2 + y[mask]**2)
    
    # Der Wert an (0,0) ist definiert als 0
    # Da result bereits mit Nullen initialisiert wurde, müssen wir nichts mehr tun
    
    return result

# Gitterparameter
n = 100  # Anzahl der Punkte in jeder Dimension
x_min, x_max = -1.0, 1.0
y_min, y_max = -1.0, 1.0

# Erstelle das Gitter
x = np.linspace(x_min, x_max, n)
y = np.linspace(y_min, y_max, n)
X, Y = np.meshgrid(x, y)

# Berechne die Funktionswerte
Z = f(X, Y)

# Begrenze die Werte für eine bessere Visualisierung
# Die Funktion kann extreme Werte nahe der Singularität annehmen
Z = np.clip(Z, -1, 1)

# Erstelle eine interaktive 3D-Darstellung mit Plotly
fig = go.Figure(data=[go.Surface(z=Z, x=X, y=Y, colorscale='viridis')])

# Passe das Layout an
fig.update_layout(
    title='3D-Darstellung der unstetigen Funktion f(x,y) = xy/(x² + y²)',
    scene=dict(
        xaxis_title='x-Achse',
        yaxis_title='y-Achse',
        zaxis_title='f(x,y)',
        zaxis=dict(range=[-1, 1]),  # Begrenze die z-Achse
        aspectratio=dict(x=1, y=1, z=0.8),
        camera=dict(
            eye=dict(x=1.5, y=1.5, z=1.2)  # Anpassung der Kameraposition
        )
    ),
    width=800,
    height=800,
    margin=dict(l=65, r=50, b=65, t=90)
)

# Füge Anmerkungen hinzu
fig.add_annotation(
    text="Unstetigkeit bei (0,0)",
    x=0,
    y=0,
    xref="x",
    yref="y",
    showarrow=True,
    arrowhead=2,
    arrowsize=1,
    arrowwidth=2,
    arrowcolor="#636363",
    ax=20,
    ay=-30
)

# Zeige die Figur an
fig.show()

# Für eine HTML-Datei:
# fig.write_html("unstetige_funktion_3d.html")
# Alternativ, um die Unstetigkeit besser zu visualisieren, können wir das Gitter auch als
# Polarkoordinaten erstellen, um den Ursprung auszulassen
def create_polar_visualization():
    # Erstelle ein Gitter in Polarkoordinaten, das den Ursprung auslässt
    r = np.linspace(0.01, 1, 50)  # Beginne nicht bei 0, um den Ursprung auszulassen
    phi = np.linspace(0, 2*np.pi, 60)
    r_grid, phi_grid = np.meshgrid(r, phi)

    # Konvertiere zu kartesischen Koordinaten
    X_polar = r_grid * np.cos(phi_grid)
    Y_polar = r_grid * np.sin(phi_grid)

    # Berechne die Funktion
    Z_polar = f(X_polar, Y_polar)

    # Erstelle die Visualisierung
    fig_polar = go.Figure(data=[go.Surface(z=Z_polar, x=X_polar, y=Y_polar, colorscale='viridis')])
    
    fig_polar.update_layout(
        title='Unstetigkeit im Ursprung: f(x,y) = xy/(x² + y²)',
        scene=dict(
            xaxis_title='x-Achse',
            yaxis_title='y-Achse',
            zaxis_title='f(x,y)',
            zaxis=dict(range=[-1, 1]),
            aspectratio=dict(x=1, y=1, z=0.8),
            camera=dict(
                eye=dict(x=1.5, y=1.5, z=1.2)
            )
        ),
        width=800,
        height=800
    )
    
    # Zeige die Figur an
    fig_polar.show()
    
    # Für eine HTML-Datei:
    # fig_polar.write_html("unstetige_funktion_polar_3d.html")

# Optional: Führe auch die Polarkoordinaten-Visualisierung aus
create_polar_visualization()
import numpy as np
import plotly.graph_objects as go

# Definiere die Funktion und ihre partiellen Ableitungen
def f(x, y):
    return x**3 + y**3 - x**2 + 2*y**2 - 5*x + y + 3

def df_dx(x, y):
    return 3*x**2 - 2*x - 5

def df_dy(x, y):
    return 3*y**2 + 4*y + 1

# Erstelle die Gitter für die Visualisierung
x = np.linspace(-2, 2, 40)
y = np.linspace(-2, 2, 40)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)

# Berechne den Gradienten an jedem Punkt
DX = df_dx(X, Y)
DY = df_dy(X, Y)

# Berechne den Betrag des Gradienten für die Farbkodierung
magnitude = np.sqrt(DX**2 + DY**2)

# Normalisiere die Gradientenvektoren für eine bessere Darstellung
# Verwende einen Skalierungsfaktor für die Pfeillänge
scale_factor = 0.2
norm = np.sqrt(DX**2 + DY**2)
norm[norm == 0] = 1  # Vermeide Division durch Null
DX_norm = DX / norm * scale_factor
DY_norm = DY / norm * scale_factor

# Dünne die Gitterpunkte aus, um die Darstellung übersichtlicher zu gestalten
skip = 5
X_sparse = X[::skip, ::skip]
Y_sparse = Y[::skip, ::skip]
DX_sparse = DX_norm[::skip, ::skip]
DY_sparse = DY_norm[::skip, ::skip]

# Erstelle ein Figure-Objekt mit zwei Subplots: 3D-Oberfläche und Konturplot mit Gradienten
fig = go.Figure(go.Contour(
        z=Z,
        x=x,
        y=y,
        colorscale='viridis',
        showscale=True,
        contours=dict(
            start=-10,
            end=10,
            size=1,
            showlabels=True
        )
    ))

# Füge Gradientenvektoren hinzu
fig.add_trace(
    go.Scatter(
        x=X_sparse.flatten(),
        y=Y_sparse.flatten(),
        mode='markers+text',
        marker=dict(
            size=1,
            color='rgba(0,0,0,0)'
        ),
        text=' ',
        showlegend=False
    )
)

# Füge Pfeile als Anmerkungen hinzu, um den Gradienten zu visualisieren
for i in range(X_sparse.shape[0]):
    for j in range(X_sparse.shape[1]):
        x_pos = X_sparse[i, j]
        y_pos = Y_sparse[i, j]
        dx = DX_sparse[i, j]
        dy = DY_sparse[i, j]
        
        # Berechne die Farbe basierend auf dem Betrag des Gradienten
        mag = np.sqrt(dx**2 + dy**2)
        arrow_color = f'rgb({int(255*mag/scale_factor/20)}, 0, {255-int(255*mag/scale_factor/20)})'
        
        fig.add_annotation(
            x=x_pos,
            y=y_pos,
            ax=x_pos + dx,
            ay=y_pos + dy,
            xref="x2",
            yref="y2",
            axref="x2",
            ayref="y2",
            showarrow=True,
            arrowhead=2,
            arrowsize=1,
            arrowwidth=1,
            arrowcolor=arrow_color
        )

# Füge einen Titel mit Erklärung hinzu
fig.update_layout(
    title_text='<b>Visualisierung des Gradienten</b><br>Der Gradient zeigt in Richtung des steilsten Anstiegs und steht senkrecht auf den Höhenlinien',
    height=600,
    width=1200,
    scene=dict(
        xaxis_title='x-Achse',
        yaxis_title='y-Achse',
        zaxis_title='f(x,y)',
        camera=dict(
            eye=dict(x=1.5, y=1.5, z=1.2)
        )
    ),
    xaxis2=dict(title='x-Achse'),
    yaxis2=dict(title='y-Achse', scaleanchor="x2", scaleratio=1),
)

# Anzeigen der Figur
fig.show()

# Optional: Speichern der Figur als HTML-Datei
# fig.write_html("gradient_visualization.html")

# Zusätzlich: Erstelle eine Animation, die zeigt, wie der Gradient immer senkrecht auf den Höhenlinien steht
# Dafür erstellen wir eine Figur mit nur dem Konturplot und einigen ausgewählten Gradienten

def create_gradient_animation():
    # Wähle einige spezifische Punkte für die Demonstration
    demo_points = [
        (-1.5, -1.5), (-1.5, 1.5), (1.5, -1.5), (1.5, 1.5),
        (0, 0), (1, 0), (0, 1), (-1, 0), (0, -1)
    ]
    
    frames = []
    
    # Erzeuge Frames für die Animation
    for i, (px, py) in enumerate(demo_points):
        # Berechne den Gradienten am ausgewählten Punkt
        grad_x = df_dx(px, py)
        grad_y = df_dy(px, py)
        
        # Normalisiere den Gradienten
        norm = np.sqrt(grad_x**2 + grad_y**2)
        grad_x_norm = grad_x / norm * scale_factor * 2
        grad_y_norm = grad_y / norm * scale_factor * 2
        
        # Erstelle einen Frame mit dem Konturplot und dem ausgewählten Gradienten
        frame = go.Frame(
            data=[
                go.Contour(
                    z=Z,
                    x=x,
                    y=y,
                    colorscale='viridis',
                    contours=dict(
                        start=-10,
                        end=10,
                        size=1,
                        showlabels=True
                    )
                ),
                go.Scatter(
                    x=[px],
                    y=[py],
                    mode='markers',
                    marker=dict(
                        size=10,
                        color='red'
                    ),
                    name='Ausgewählter Punkt'
                )
            ],
            layout=go.Layout(
                annotations=[
                    dict(
                        x=px,
                        y=py,
                        ax=px + grad_x_norm,
                        ay=py + grad_y_norm,
                        xref="x",
                        yref="y",
                        axref="x",
                        ayref="y",
                        showarrow=True,
                        arrowhead=2,
                        arrowsize=2,
                        arrowwidth=2,
                        arrowcolor='red'
                    ),
                    dict(
                        x=0.5,
                        y=0.9,
                        xref="paper",
                        yref="paper",
                        text=f"Gradient am Punkt ({px}, {py}): ({grad_x:.2f}, {grad_y:.2f})",
                        showarrow=False,
                        font=dict(size=14)
                    )
                ]
            ),
            name=f"frame{i}"
        )
        frames.append(frame)
    
    # Erstelle die Animation
    fig_animation = go.Figure(
        data=[
            go.Contour(
                z=Z,
                x=x,
                y=y,
                colorscale='viridis',
                contours=dict(
                    start=-10,
                    end=10,
                    size=1,
                    showlabels=True
                )
            ),
            go.Scatter(
                x=[demo_points[0][0]],
                y=[demo_points[0][1]],
                mode='markers',
                marker=dict(
                    size=10,
                    color='red'
                ),
                name='Ausgewählter Punkt'
            )
        ],
        layout=go.Layout(
            title_text='<b>Animation des Gradienten</b><br>Der Gradient steht immer senkrecht auf den Höhenlinien',
            updatemenus=[dict(
                type="buttons",
                buttons=[dict(
                    label="Play",
                    method="animate",
                    args=[None, {"frame": {"duration": 1000, "redraw": True}, "fromcurrent": True}],
                )]
            )],
            xaxis=dict(title='x-Achse', range=[-2, 2]),
            yaxis=dict(title='y-Achse', range=[-2, 2], scaleanchor="x", scaleratio=1),
            height=600,
            width=800,
            annotations=[
                dict(
                    x=demo_points[0][0],
                    y=demo_points[0][1],
                    ax=demo_points[0][0] + df_dx(demo_points[0][0], demo_points[0][1]) / np.sqrt(df_dx(demo_points[0][0], demo_points[0][1])**2 + df_dy(demo_points[0][0], demo_points[0][1])**2) * scale_factor * 2,
                    ay=demo_points[0][1] + df_dy(demo_points[0][0], demo_points[0][1]) / np.sqrt(df_dx(demo_points[0][0], demo_points[0][1])**2 + df_dy(demo_points[0][0], demo_points[0][1])**2) * scale_factor * 2,
                    xref="x",
                    yref="y",
                    axref="x",
                    ayref="y",
                    showarrow=True,
                    arrowhead=2,
                    arrowsize=2,
                    arrowwidth=2,
                    arrowcolor='red'
                ),
                dict(
                    x=0.5,
                    y=0.9,
                    xref="paper",
                    yref="paper",
                    text=f"Gradient am Punkt ({demo_points[0][0]}, {demo_points[0][1]}): ({df_dx(demo_points[0][0], demo_points[0][1]):.2f}, {df_dy(demo_points[0][0], demo_points[0][1]):.2f})",
                    showarrow=False,
                    font=dict(size=14)
                )
            ]
        ),
        frames=frames
    )
    
    # Anzeigen der Animation
    fig_animation.show()
    
    # Optional: Speichern der Animation als HTML-Datei
    # fig_animation.write_html("gradient_animation.html")

# Uncomment to create the animation
create_gradient_animation()